`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2017/10/23 15:21:30
// Design Name: 
// Module Name: controller
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
import structs::*;

module controller(
	input wire clk,rst,
	input datapath_sign_out_t datapathout,
	output controller_sign_out_t controllerout
    );
	
	
	control_sign_t controlsignD;
	assign controllerout.branchD = controlsignD.branch;
	assign controllerout.jumpD = controlsignD.jump;
	assign controllerout.regdstD = controlsignD.regdst;
	assign controllerout.cmpcontrolD = controlsignD.cmpcontrol;
	assign controllerout.jumpregD = controlsignD.jumpreg;
	assign controllerout.invalidD= controlsignD.invalid;
	assign controllerout.breakpointD= controlsignD.breakpoint;
	assign controllerout.syscallD= controlsignD.syscall;
	assign controllerout.eretD= controlsignD.eret;
	assign controllerout.jumplinkD = controlsignD.jumplink;
	assign controllerout.jumplinkregD = controlsignD.jumplinkreg;
	wire[4:0] alucontrolD;

	//execute stage
	wire memwriteE;
    
	maindec md(
		datapathout.opD, datapathout.functD,
		datapathout.instrD,
		controlsignD
		);
	aludec ad(datapathout.instrD,alucontrolD);
    
    // datapathout.equalD includes results of beq, bne, bgtz, bgez, bltz, blez
	assign controllerout.pcsrcD = controllerout.branchD & datapathout.equalD;

	//pipeline registers
	flopenrc #(20) regE(
		clk,rst,
		~datapathout.stallE,
		datapathout.flushE,
		{controlsignD.memtoreg,controlsignD.memwrite,controlsignD.alusrc,controlsignD.regdst,controlsignD.regwrite,alucontrolD,controlsignD.lordD,controlsignD.storeD,controlsignD.jumplink,controlsignD.jumplinkreg,controlsignD.cp0we,controlsignD.cp0read},
		{controllerout.memtoregE,memwriteE,controllerout.alusrcE,controllerout.regdstE,controllerout.regwriteE,controllerout.alucontrolE,controllerout.lordE,controllerout.storeE,controllerout.jumplinkE,controllerout.jumplinkregE,controllerout.cp0weE,controllerout.cp0readE}
		);
	flopenrc #(16) regM(
		clk,rst,
		~datapathout.stallM,
		datapathout.flushM,
		{controllerout.memtoregE,memwriteE,controllerout.regwriteE,controllerout.lordE,controllerout.storeE,controllerout.cp0weE,controllerout.cp0readE},
		{controllerout.memtoregM,controllerout.memwriteM,controllerout.regwriteM,controllerout.lordM,controllerout.storeM,controllerout.cp0weM,controllerout.cp0readM}
		);
	flopenrc #(9) regW(
		clk,rst,
		~datapathout.stallW,
		datapathout.flushW,
		{controllerout.memtoregM,controllerout.regwriteM,controllerout.cp0readM},
		{controllerout.memtoregW,controllerout.regwriteW,controllerout.cp0readW}
		);
endmodule
